package cn.wmw.xyy.service.impl;

import cn.wmw.result.JsonResult;
import cn.wmw.utils.CodeGenerateUtils;
import cn.wmw.xyy.bo.CourseOrderExtParamsBo;
import cn.wmw.xyy.bo.CourseOrderPayBo;
import cn.wmw.xyy.bo.KillCoursePreOrderBo;
import cn.wmw.xyy.domain.Course;
import cn.wmw.xyy.domain.CourseMarket;
import cn.wmw.xyy.domain.CourseOrder;
import cn.wmw.xyy.domain.CourseOrderItem;
import cn.wmw.xyy.dto.CourseOrderDto;
import cn.wmw.xyy.dto.KillCourseOrderDto;
import cn.wmw.xyy.exception.GlobalExceptionEnum;
import cn.wmw.xyy.feign.CourseFeignClient;
import cn.wmw.xyy.mapper.CourseOrderMapper;
import cn.wmw.xyy.service.ICourseOrderItemService;
import cn.wmw.xyy.service.ICourseOrderService;
import cn.wmw.xyy.utils.AssertUtil;
import cn.wmw.xyy.vo.CourseInfoVo;
import cn.wmw.xyy.vo.CourseOrderInfoVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wmw
 * @since 2023-01-09
 */
@Service
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private CourseFeignClient feignClient;

    @Autowired
    private ICourseOrderItemService courseOrderItemService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Override
    public String placeOrder(CourseOrderDto courseOrderDto) {
        Long loginId = 7L;
        List<Long> courseId = courseOrderDto.getCourseIds();
        String ids = courseId.stream().map(String::valueOf).collect(Collectors.joining(","));
        Integer payType = courseOrderDto.getPayType();
        String token = courseOrderDto.getToken();
        String key = loginId+":"+ids;
        Object objtem = redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(objtem, GlobalExceptionEnum.ERROR);
        AssertUtil.isEquals(token,objtem.toString(),GlobalExceptionEnum.ERROR);
        redisTemplate.delete(key);
        JsonResult info = feignClient.info(ids);
        AssertUtil.isTrue(info.isSuccess(),GlobalExceptionEnum.ERROR);
        Object data = info.getData();
        AssertUtil.isNotNull(data,GlobalExceptionEnum.ERROR);
        //获取课程的相关信息
        CourseOrderInfoVo courseOrderInfoVo = JSON.parseObject(JSON.toJSONString(data), CourseOrderInfoVo.class);
        List<CourseInfoVo> courseInfos = courseOrderInfoVo.getCourseInfos();
        BigDecimal totalAmount = courseOrderInfoVo.getTotalAmount();
        //存课程订单表
        CourseOrder courseOrder = new CourseOrder();
        Date date = new Date();
        String orderSn = CodeGenerateUtils.generateOrderSn(loginId);
        courseOrder.setCreateTime(date);
        courseOrder.setOrderNo(orderSn);
        courseOrder.setTotalAmount(totalAmount);
        courseOrder.setTotalCount(courseId.size());
        courseOrder.setStatusOrder(CourseOrder.WAIT_PAY);
        courseOrder.setUserId(loginId);
        courseOrder.setVersion(0);
        courseOrder.setPayType(payType);
        String titleTmp = "购买课程 [%s] , 共支付[%s] 元";
        String courseNames = courseInfos.stream().map(e -> e.getCourse().getName()).collect(Collectors.joining(";"));
        String title = String.format(titleTmp, courseNames, totalAmount);
        courseOrder.setTitle(title);
//        insert(courseOrder);
        List<CourseOrderItem> courseOrderItems = courseOrder.getCourseOrderItems();
        courseInfos.forEach(e->{
            Course course = e.getCourse();
            CourseMarket courseMarket = e.getCourseMarket();
            CourseOrderItem courseOrderItem = new CourseOrderItem();
            courseOrderItem.setOrderId(courseOrder.getId());
            courseOrderItem.setAmount(courseMarket.getPrice());
            courseOrderItem.setCount(1);
            courseOrderItem.setCreateTime(date);
            courseOrderItem.setCourseId(course.getId());
            courseOrderItem.setCourseName(course.getName());
            courseOrderItem.setCoursePic(course.getPic());
            courseOrderItem.setVersion(0);
            courseOrderItem.setOrderNo(orderSn);
            courseOrderItems.add(courseOrderItem);
        });
//        courseOrderItemService.insertBatch(courseOrderItems);
        CourseOrderPayBo courseOrderPayBo = new CourseOrderPayBo();
        BeanUtils.copyProperties(courseOrder,courseOrderPayBo);
        Message<CourseOrderPayBo> message = MessageBuilder.withPayload(courseOrderPayBo).build();
        rocketMQTemplate.sendMessageInTransaction("tx-course-order-pay-group",
                "course-order-pay-topic:course-order-pay-tag",
                message,courseOrder);

        // todo 30分钟回查是否支付成功,支付成功修改课程和用户的中间表
        try {
            SendResult sendResult = rocketMQTemplate.syncSend(
                    "pay-timeout-topic:pay-timeout-tag",
                    message,
                    2000,
                    4);
            if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)){
                // 重试，不行再通知管理员
            }
        } catch (Exception e) {
            // 重试，不行再通知管理员
            e.printStackTrace();
        }
        return orderSn;
    }

    @Override
    public void insertOrderAndOrderItem(CourseOrder courseOrder) {
        String orderNo = courseOrder.getOrderNo();
        CourseOrder selectCourseOrder = selectByOrderNo(orderNo);
        AssertUtil.isNull(selectCourseOrder,GlobalExceptionEnum.ERROR);
        insert(courseOrder);
        List<CourseOrderItem> courseOrderItems = courseOrder.getCourseOrderItems();
        courseOrderItems.forEach(e->{
            e.setOrderId(courseOrder.getId());
        });
        courseOrderItemService.insertBatch(courseOrderItems);
    }

    public CourseOrder selectByOrderNo(String orderNo) {

        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",orderNo);
        CourseOrder courseOrder = selectOne(wrapper);
        return courseOrder;
    }

    @Override
    public String killPlaceOrder(KillCourseOrderDto killCourseOrderDto) {
        Integer payType = killCourseOrderDto.getPayType();
        String token = killCourseOrderDto.getToken();
        String orderNo = killCourseOrderDto.getOrderNo();
        // 1.参数校验，使用JSR303
        Object o = redisTemplate.opsForValue().get("preOrder:" + orderNo);
        AssertUtil.isNotNull(o, GlobalExceptionEnum.ERROR);
        KillCoursePreOrderBo killCoursePreOrderBo = JSON.parseObject(JSON.toJSONString(o), KillCoursePreOrderBo.class);
        Long courseId = killCoursePreOrderBo.getCourseId();
        Long loginId = killCoursePreOrderBo.getUserId();
        // 2.业务校验
        String key = loginId + ":" + courseId;
        Object objTmp = redisTemplate.opsForValue().get(key);
        // 2.1.判断是否是第一次进入
        AssertUtil.isNotNull(objTmp, GlobalExceptionEnum.ERROR);
        // 2.2.判断令牌是否相等
        AssertUtil.isEquals(token, objTmp.toString(), GlobalExceptionEnum.ERROR);
        redisTemplate.delete(key);

        // 4.保存课程主订单
        CourseOrder courseOrder = new CourseOrder();
        BigDecimal killPrice = killCoursePreOrderBo.getKillPrice();
        String courseName = killCoursePreOrderBo.getCourseName();
        Date date = new Date();
        courseOrder.setCreateTime(date);
        courseOrder.setOrderNo(orderNo);
        courseOrder.setTotalAmount(killPrice);
        courseOrder.setTotalCount(killCoursePreOrderBo.getKillLimit());
        courseOrder.setStatusOrder(CourseOrder.WAIT_PAY);
        courseOrder.setUserId(loginId);
        courseOrder.setVersion(0);
        courseOrder.setPayType(payType);
        String titleTmp = "购买课程 [%s] , 支付[%s] 元";
        String title = String.format(titleTmp, courseName, killPrice);
        courseOrder.setTitle(title);
        //insert(courseOrder);
        // 5.保存订单快照
        CourseOrderItem courseOrderItem = new CourseOrderItem();
        // courseOrderItem.setOrderId(courseOrder.getId());
        courseOrderItem.setAmount(killPrice);
        courseOrderItem.setCount(1);
        courseOrderItem.setCreateTime(date);
        courseOrderItem.setCourseId(courseId);
        courseOrderItem.setCourseName(courseName);
        courseOrderItem.setCoursePic(killCoursePreOrderBo.getCoursePic());
        courseOrderItem.setVersion(0);
        courseOrderItem.setOrderNo(orderNo);
        courseOrder.getCourseOrderItems().add(courseOrderItem);

        CourseOrderPayBo courseOrderPayBo = new CourseOrderPayBo();
        BeanUtils.copyProperties(courseOrder, courseOrderPayBo);

        // 设置扩展参数
        CourseOrderExtParamsBo courseOrderExtParamsBo = new CourseOrderExtParamsBo();
        courseOrderExtParamsBo.setOrderNo(orderNo);
        courseOrderExtParamsBo.setUserId(loginId);
        courseOrderExtParamsBo.setCourseIds(courseId.toString());
        courseOrderPayBo.setCourseOrderExtParamsBo(courseOrderExtParamsBo);
        Message<CourseOrderPayBo> message = MessageBuilder.withPayload(courseOrderPayBo).build();
        // 6.调用支付服务，发起支付
        rocketMQTemplate.sendMessageInTransaction(
                "tx-course-order-pay-group",
                "course-order-pay-topic:course-order-pay-tag",
                message,
                courseOrder);
        try {
            // 7.定时3分钟，检查支付是否成功
            SendResult sendResult = rocketMQTemplate.syncSend(
                    "pay-timeout-handler-topic:pay-timeout-handler-tag",
                    message,
                    2000,
                    4);
            if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)){
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return orderNo;
    }
}
